
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>JWT学习指南 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>JWT学习指南 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">什么是JSON Web Token (JWT)？它的主要用途是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">JSON Web Token (JWT) 是一个开放标准 (RFC 7519)，它定义了一种紧凑且独立的方式，用于在各方之间作为JSON对象安全地传输信息。这些信息可以通过数字签名进行验证和信任。通俗地说，它是一个含签名并携带用户信息的加密串，用于在客户端和服务器之间进行身份验证。</div>
          </div>
          <div class="card-source">来源: 什么是JWT</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">结构</div>
          <div class="card-question">一个标准的JWT由哪三个部分组成？它们之间是如何分隔的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">结构</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">一个JWT由三部分组成：Header (头部)、Payload (负载) 和 Signature (签名)。这三个部分之间使用点（.）进行分隔，形成一个完整的字符串。</div>
          </div>
          <div class="card-source">来源: JWT结构</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">JWT中的Signature（签名）部分是如何生成的？它的核心作用是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">签名是通过将编码后的头部（Header）和编码后的负载（Payload）与一个密钥（secret）结合，并使用指定的签名算法（如HMACSHA256）计算得出的。其核心作用是验证消息的完整性并确认发送者的身份，确保令牌没有被篡改。</div>
          </div>
          <div class="card-source">来源: JWT结构</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">JWT如何帮助实现无状态（Stateless）认证？与传统的Session认证相比有何优势？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">JWT是无状态的，因为它在生成后将所有必要的用户信息（如ID、角色）包含在自身（Payload）中。客户端每次请求都携带此Token，服务器通过解析Token即可验证用户，无需在服务器端保存任何Session信息。这减轻了服务器的负担，与需要服务器存储Session的传统认证方式相比，扩展性更好。</div>
          </div>
          <div class="card-source">来源: JWT解决了什么问题</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">当服务器收到一个带有JWT的请求时，会执行哪些关键的验证步骤？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">服务器验证JWT时会执行以下几个关键步骤：<br>1. 验证Token的格式是否正确。<br>2. 验证Token的签名是否有效，以确保Token未被篡改。<br>3. 验证Token是否已过期。<br>4. 验证Token中携带的用户信息是否具有执行该请求的权限。</div>
          </div>
          <div class="card-source">来源: JWT认证</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">在客户端与服务器通信时，JWT通常被放在HTTP请求的哪个部分？具体格式是怎样的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">JWT通常放在HTTP请求的头部（Header）中，具体形式为 `Authorization: Bearer <token>`。这样做可以方便地与其他参数区分，并有助于解决跨域等问题。</div>
          </div>
          <div class="card-source">来源: JWT结构</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">文档中提到了在进行JWT认证时可能遇到的四种常见异常是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">认证时常见的四种异常是：<br>- SignatureVerificationException: 签名不一致异常。<br>- TokenExpiredException: 令牌过期异常。<br>- AlgorithmMismatchException: 算法不匹配异常。<br>- InvalidClaimException: 失效的payload异常。</div>
          </div>
          <div class="card-source">来源: 认证token</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">请解释JWT自校验（self-validation）的核心原理。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">JWT自校验的核心原理是：服务器在收到Token后，会从中解析出Header和Payload。然后，服务器使用自己保存的密钥（secret）对解析出的Header和Payload重新进行一次签名计算。最后，将新生成的签名与Token中原始的签名进行对比。如果两者完全一致，则证明Token是合法且未被篡改的。</div>
          </div>
          <div class="card-source">来源: JWT源码</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">如何解决一个用户在多个设备登录时产生的多Token有效问题？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">可以通过在后端引入一个集中式存储（如Redis）来解决。用户每次成功登录时，生成一个新的Token，并将这个Token存入Redis（以用户名等作为key）。在进行路由校验时，不仅要校验Token本身的合法性，还要从Redis中获取该用户的最新Token，并与当前请求的Token进行对比。只有两者一致时，才认证通过，从而确保只有最新的Token有效。</div>
          </div>
          <div class="card-source">来源: 解决多用户登录的问题</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
